package com.misty.api.aop;

import cn.hutool.core.util.ObjectUtil;
import com.misty.common.Util.SecurityUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @ClassName : ApiLogAspect
 * @Description :
 * @Author :
 * @Date: 2022-12-14 08:52
 */
@Component
@Aspect
@Slf4j
public class ApiLogAspect {

    /**
     * 指定切面对象，Controller层所有暴露给前端的接口方法
     */
    @Pointcut("execution(public * com.misty.*.controller.*.*.*(..))")
    public void pointcut() {}

    /**
     * 记录接口入参日志
     */
    @Before("pointcut()")
    public void beforeMethod(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getMethod().getName();
        log.info("================调用 {} 方法开始===============",methodName);

        ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = sra.getRequest();
        // 获取接口路径
        String path = request.getRequestURI();
        // 获取登录用户
        String username = "";
        if(SecurityUtil.judgeLogin()){
            username = SecurityUtil.getAuthentication().getName();
        }
        // 获取请求参数
        Object[] args = joinPoint.getArgs();
        // 获取时间
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String time = LocalDateTime.now().format(formatter);
//        long time = LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        // 记录入参日志
        log.info(String.format("发起请求->用户:[%s],时间:[%s],路径:[%s],参数:[%s].",
                username, time, path, ObjectUtil.isNull(args)?"": String.valueOf(args)));
    }

    @After(value = "pointcut()")
    public void afterMethod(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getMethod().getName();
        log.info("================调用 {} 方法结束===============",methodName);
    }

    /**
     * 记录接口出参日志
     */
    @AfterReturning(value="pointcut()" ,returning="result")
    public void afterReturning(Object result) {
        ServletRequestAttributes sra = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = sra.getRequest();
        // 获取接口路径
        String path = request.getRequestURI();
        // 获取登录用户
        String username = "";
        if(SecurityUtil.judgeLogin()){
            username = SecurityUtil.getAuthentication().getName();
        }
        // 记录入参日志
        // 获取时间
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String time = LocalDateTime.now().format(formatter);
//        long time = LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
        // 记录出参日志
//        log.info(String.format("发起响应->用户:[%s],时间:[%s],路径:[%s],参数:[%s].",
//                username, time, path, ObjectUtil.isNull(result)?"":String.valueOf(result)));
        log.info(String.format("发起响应->用户:[%s],时间:[%s],路径:[%s],参数:[%s].",
                username, time, path, ""));
    }

    /**
     * 记录接口抛出的异常
     */
    @AfterThrowing(value="pointcut()" ,throwing="e")
    public void afterThrowing(JoinPoint joinPoint, Exception e) {
        // 获取方法名(也可以像上面一样获取接口路径)
        String method = String.format("%s.%s", joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName());
        // 记录异常日志
        log.info(String.format("异常->方法:[%s],异常:[%s].", method, e.getMessage()));
    }
}
